﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using Wicresoft.SelfService.WFInterface;
using Wicresoft.SelfService.WorkFlow;
using System.Threading;
using System.ServiceModel.Persistence;
using System.Xml.Linq;
using System.IO;

namespace Wicresoft.SelfService.WFHost.Code
{
    public class ApproveFlowHost
    {
        //static IDictionary<Guid, WorkflowApplication> instances;

        static ApproveFlowHost()
        {
            //instances = new Dictionary<Guid, WorkflowApplication>();
            MyInitialize();
            Log.Debug("ApproveFlowHost", "The Host Has Running");
        }

        public WorkflowApplication LoadInstance(Guid instanceId)
        {
            //if (instances.ContainsKey(instanceId))
            //    return instances[instanceId];

            WorkflowApplication instance = new WorkflowApplication(new SelfService.WorkFlow.SelfService());

            XmlWorkflowInstanceStore instStore = new XmlWorkflowInstanceStore(instanceId);
            instance.InstanceStore = instStore;

            XmlPersistenceParticipant xmlPersistenceParticipant = new XmlPersistenceParticipant(instanceId);
            instance.Extensions.Add(xmlPersistenceParticipant);

            instance.PersistableIdle += OnIdleAndPersistable;
            instance.Completed += OnWorkflowCompleted;
            instance.Idle += OnIdle;
            instance.OnUnhandledException += OnUnhandledEx;
            instance.Unloaded += OnUnloaded;

            instance.Load(instanceId);
            //instances.Add(instanceId, instance);
            return instance;
        }

        public RequestResult CreateAndRun(RequestParam requestParam)
        {
            #region CreateVerify
            if (requestParam == null)
            {
                return new RequestResult
                {
                    ErrorMsg = "The Parameter Can't be Null."
                };
            }
            if (requestParam.SecurityCode == null)
            {
                return new RequestResult
                {
                    ErrorMsg = "Please enter SecurityCode."
                };
            }
            if (requestParam.SecurityCode != "fjyc.wicresoft")
            {
                return new RequestResult
                {
                    ErrorMsg = "Please enter Proper SecurityCode."
                };
            }
            if (requestParam.ApplicationId == null)
            {
                return new RequestResult
                {
                    ErrorMsg = "Please enter ApplicationId"
                };
            }
            #endregion

            AutoResetEvent arResetEvent = new AutoResetEvent(false);
            RequestResult requestResult = new RequestResult();
            ActionResult actionResult = new ActionResult();

            IDictionary<string, object> inputs = new Dictionary<string, object>();
            inputs.Add("Rp", requestParam);
            //inputs.Add("Rr", requestResult);

            Activity wf = new SelfService.WorkFlow.SelfService();
            WorkflowApplication instance = new WorkflowApplication(wf, inputs);

            XmlWorkflowInstanceStore store = new XmlWorkflowInstanceStore(instance.Id);
            instance.InstanceStore = store;

            XmlPersistenceParticipant xmlPersistenceParticipant = new XmlPersistenceParticipant(instance.Id);
            instance.Extensions.Add(xmlPersistenceParticipant);

            instance.PersistableIdle += OnIdleAndPersistable;
            instance.Completed += OnWorkflowCompleted;
            instance.Idle += OnIdle;
            instance.OnUnhandledException += OnUnhandledEx;
            instance.Unloaded += OnUnloaded;

            //instances.Add(instance.Id, instance);

            WorkflowCache.WFAutoResetEvents.Add(instance.Id, arResetEvent);
            WorkflowCache.WFActionResults.Add(instance.Id, actionResult);
            //SaveInstanceId(instance.Id);

            Log.Debug("ApproveFlowHost", "The WorkFlow {0} Has Created And Begin to Run.", instance.Id);
            instance.Run();

            arResetEvent.WaitOne(30000);
            actionResult = WorkflowCache.WFActionResults[instance.Id];

            if (actionResult != null)
            {
                requestResult.FlowInstanceId = instance.Id;
                requestResult.Status = actionResult.Status;
                requestResult.Step = actionResult.Step;
                requestResult.RequestCode = actionResult.RequestCode;
                requestResult.ErrorMsg = actionResult.ErrorMsg;
            }

            Log.Debug("ApproveFlowHost", "The WorkFlow {0}  is Return the First.", instance.Id);
            return requestResult;
        }

        #region Event
        public void OnIdle(WorkflowApplicationIdleEventArgs e)
        {
            Console.WriteLine("Idle:停顿");
        }

        public PersistableIdleAction OnIdleAndPersistable(WorkflowApplicationIdleEventArgs e)
        {
            Console.WriteLine("PersistableIdle:停顿但是可以继续");
            return PersistableIdleAction.Unload;
        }

        public UnhandledExceptionAction OnUnhandledEx(WorkflowApplicationUnhandledExceptionEventArgs e)
        {
            Console.WriteLine(e.UnhandledException.ToString());
            return UnhandledExceptionAction.Cancel;
        }

        public void OnWorkflowCompleted(WorkflowApplicationCompletedEventArgs e)
        {
            Console.WriteLine("Completed：完成");
            //RemoveInstanceId(e.InstanceId);
        }

        public void OnUnloaded(WorkflowApplicationEventArgs e)
        {
            AutoResetEvent _event = WorkflowCache.WFAutoResetEvents[e.InstanceId];

            if (_event != null)
            {
                _event.Set();
            }
            Console.WriteLine("Unloaded：卸载");
            //instances.Remove(e.InstanceId);
        }
        #endregion

        public ActionResult UpdateForApprove(ActionParam actionParam)
        {
            ActionResult actionResult;

            #region UpdateVerify
            if (actionParam == null)
            {
                return new ActionResult
                {
                    ErrorMsg = "The Parameter Can't be Null."
                };
            }
            if (actionParam.SecurityCode != "fjyc.wicresoft")
            {
                return new ActionResult
                {
                    ErrorMsg = "Please enter Proper SecurityCode."
                };
            }
            if (actionParam.RequestCode == null)
            {
                return new ActionResult
                {
                    ErrorMsg = "Please enter RequestCode."
                };
            }
            if (actionParam.CurrentStep == null)
            {
                return new ActionResult
                {
                    ErrorMsg = "Please enter CurrentStep."
                };
            }
            if (actionParam.CurrentStep == "local_interface" && actionParam.Action != "Reject" && actionParam.Action != "Approve" && actionParam.Action != "Cancel")
            {
                return new ActionResult
                {
                    ErrorMsg = "Please enter Proper action."
                };
            }
            if (actionParam.CurrentStep != "local_interface" && actionParam.Action != "Reject" && actionParam.Action != "Approve" && actionParam.Action != "RollBack")
            {
                return new ActionResult
                {
                    ErrorMsg = "Please enter Proper action."
                };
            }

            ActionResult re = GetLastResult(actionParam.FlowInstanceId);
            if (re != null && re.RequestCode == actionParam.RequestCode)
            {
                re.ErrorMsg = "The RequestCode of Flow <" + actionParam.FlowInstanceId + ">is Repeat." + re.ErrorMsg;
                return re;
            }
            #endregion

            try
            {
                WorkflowApplication instance = this.LoadInstance(actionParam.FlowInstanceId);

                string bookmarkName = "waitingFor_" + actionParam.CurrentStep;

                Log.Debug("ApproveFlowHost", "The WorkFlow {0}  will ResumeBookmark {1}.", instance.Id, bookmarkName);
                BookmarkResumptionResult bkResult = instance.ResumeBookmark(bookmarkName, actionParam);
                if (bkResult == BookmarkResumptionResult.NotFound) throw new Exception("The bookmark resumption was not scheduled because the bookmark could not be found.:" + bookmarkName + ".(Please cheack CurrentStep)");
                if (bkResult == BookmarkResumptionResult.NotReady) throw new Exception("The bookmark resumption was not scheduled because the runtime has not yet created the bookmark.:" + bookmarkName + ".(Please cheack CurrentStep)");

                var ware = WorkflowCache.WFAutoResetEvents[instance.Id];
                if (!ware.Equals(null))
                {
                    ware.WaitOne(30000);
                    actionResult = WorkflowCache.WFActionResults[instance.Id];
                }
                else
                {
                    actionResult = new ActionResult();
                    actionResult.ErrorMsg = "Can't find the AutoResetEvent";
                }

                Log.Debug("ApproveFlowHost", "The WorkFlow {0} is Return Normal after ResumeBookmark {1}.", instance.Id, bookmarkName);
            }
            catch (PersistenceException ex)
            {
                actionResult = new ActionResult();
                actionResult.ErrorMsg = "Can't find the WorkflowApplication :" + actionParam.ToString();

                Log.Error("ApproveFlowHost", "Workflow {0} Error: Can't find.", actionParam.FlowInstanceId);
            }
            catch (Exception ex)
            {
                actionResult = new ActionResult();
                actionResult.ErrorMsg = ex.Message.ToString();

                Log.Error("ApproveFlowHost", "The WorkFlow {0} Error: {1}.", actionParam.FlowInstanceId, ex.Message.ToString());
            }

            return actionResult;
        }

        /// <summary>
        /// Filter string function
        /// </summary>
        /// <param name="str"> filter string</param>
        /// <returns></returns>
        //public static string CheckString(string str)
        //{
        //    str = str.Replace("'", "");
        //    str = str.Replace("select ", "");
        //    str = str.Replace("insert ", "");
        //    str = str.Replace("delete ", "");
        //    str = str.Replace(@"count\(", "");
        //    str = str.Replace("drop table ", "");
        //    str = str.Replace("update ", "");
        //    str = str.Replace("truncate ", "");
        //    str = str.Replace(@"asc\(", "");
        //    str = str.Replace(@"mid\(", "");
        //    str = str.Replace(@"char\(", "");
        //    str = str.Replace("xp_cmdshell", "");
        //    str = str.Replace("xp_dirtree", "");
        //    str = str.Replace("exec master", "");
        //    str = str.Replace("net localgroup administrators", "");
        //    str = str.Replace(" and ", "");
        //    str = str.Replace("net user", "");
        //    str = str.Replace(" or ", "");
        //    str = str.Replace("system_user", "");
        //    str = str.Replace("IS_SRVROLEMEMBER ", "");
        //    str = str.Replace(@"db_name\(", "");
        //    str = str.Replace(@"substring\(", "");
        //    return str;
        //}

        #region xml File
        static void MyInitialize()
        {
            if (WorkflowCache.WFAutoResetEvents.Count == 0)
            {
                XElement doc = IOHelper.Load();
                IEnumerable<string> instanceId =
                                        from r in doc.Elements("Result")
                                        where r.Attribute("status").Value == "active"
                                        select r.Attribute("id").Value.ToString();

                foreach (string id in instanceId)
                {
                    WorkflowCache.WFAutoResetEvents.Add(new Guid(id), new AutoResetEvent(false));
                }
            }
            if (WorkflowCache.WFActionResults.Count == 0)
            {
                XElement doc = IOHelper.Load();
                IEnumerable<string> instanceId =
                                        from r in doc.Elements("Result")
                                        where r.Attribute("status").Value == "active"
                                        select r.Attribute("id").Value.ToString();

                foreach (var id in instanceId)
                {
                    WorkflowCache.WFActionResults.Add(new Guid(id), new ActionResult());
                }
            }
        }

        public ActionResult GetLastResult(Guid Id)
        {
            ActionResult actionResult = null;

            XElement doc = IOHelper.Load();
            IEnumerable<XElement> current =
                                    from r in doc.Elements("Result")
                                    where r.Attribute("id").Value.Equals(Id.ToString())
                                    select r;
            if (current.Count() == 1)
            {
                foreach (XElement xe in current)
                {
                    actionResult = new ActionResult
                    {
                        RequestCode = xe.Element("RequestCode").Value,
                        ErrorMsg = xe.Element("ErrorMsg").Value,
                        Status = xe.Element("WFStatus").Value,
                        Step = xe.Element("Step").Value
                    };
                }
            }

            return actionResult;
        }
        #endregion
    }
}
